/**
 * 
 */
package Phase2;

import java.io.Serializable;

import org.junit.Assert;


/**
 * 
 * State for when a node is an edge node with down pointers
 * 
 * 
 * @author byu.ryanpadilla
 *
 */

public class DownState implements NodeState, Serializable
{
	private static final long serialVersionUID = 1L;
	private static NodeState singleton;
	//id of lowest down pointer
	private Node high;
	//id of parent Id + 1
	private int low;
	

	/**
	 * private constructor
	 */
	private DownState()
	{
		
	}

	/**
	 * returns a singleton for DownState
	 * @return a reference to the DownState singleton
	 * @pre none
	 * @post return reference to the DownState singleton
	 */
	public static NodeState getState()
	{
		if(singleton == null)
		{
			singleton = new DownState();
		}
		return singleton;
	}
	@Override
	public boolean lockState(Node callingNode, boolean rootAccess)
		throws InterruptedException 
	{
		return callingNode.acquireAccessPriviledge(rootAccess);
	}
	
	/**
	 * @param callingNode - node to goRight() from
	 * @see Phase2.NodeState#goRight(Phase2.Node)
	 * @pre callingNode.state instanceOf(DownState)
	 * @post return instance of NodeOrRange to goRight to
	 */
	@Override
	public NodeOrRange goRight(Node callingNode, boolean rootAccess) throws InterruptedException
	{				
		low = callingNode.getParent(rootAccess).getId(rootAccess) + 1;
		NodeList down = callingNode.getDownPointers(rootAccess);
		if(down.size() > 0)
		{
			high = down.getMin();
		}
		//Should NEVER be reached, this detects error cases that might come up but CANNOT reasonable be test
		else
		{
			callingNode.releaseAccessPriviledge();
			throw new IllegalStateException("goRight() DownState method called when" 
					+ " there are no Down Pointers.");
		}

		//need to return a range from low to high not a Node
		callingNode.releaseAccessPriviledge();
		return new InsertionRange(low, high);
	}
	
	/**
	 * checks if the node's is correctly assigned an downState
	 * @param node checks this node
	 * @return whether it is in an downState or not
	 * @pre node != null, node is of the correct state
	 * @post return true if it is the correct state, otherwise false
	 */
	public boolean assertState(Node node) throws InterruptedException
	{
		boolean rootAccess = true;
		
		Assert.assertTrue(node != null);
		
		Assert.assertTrue(node.getDownPointers(rootAccess).size() > 0);
		
		Assert.assertTrue(node.getUpPointers(rootAccess).size() == 0);
		
		Assert.assertTrue(node.getNeighbours(rootAccess).size() > 0);		
		
		return true;
	}
	
	/**
	 * Returns a string representation of the state
	 * @return "DownState"
	 * @pre None
	 * @post return "DownState"
	 */
	public String toString()
	{
		return "DownState";
	}

}
